home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gdevddrw.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  19.1 KB  |  655 lines

  1. /* Copyright (C) 1989, 1995, 1996, 1997, 1998, 1999 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gdevddrw.c,v 1.2 2000/09/19 19:00:12 lpd Exp $ */
  20. /* Default polygon and image drawing device procedures */
  21. #include "math_.h"
  22. #include "memory_.h"
  23. #include "gx.h"
  24. #include "gpcheck.h"
  25. #include "gserrors.h"
  26. #include "gsrect.h"
  27. #include "gxfixed.h"
  28. #include "gxmatrix.h"
  29. #include "gxdcolor.h"
  30. #include "gxdevice.h"
  31. #include "gxiparam.h"
  32. #include "gxistate.h"
  33.  
  34. #define SWAP(a, b, t)\
  35.   (t = a, a = b, b = t)
  36.  
  37. /* ---------------- Polygon and line drawing ---------------- */
  38.  
  39. /* Define the 'remainder' analogue of fixed_mult_quo. */
  40. private fixed
  41. fixed_mult_rem(fixed a, fixed b, fixed c)
  42. {
  43.     /* All kinds of truncation may happen here, but it's OK. */
  44.     return a * b - fixed_mult_quo(a, b, c) * c;
  45. }
  46.  
  47. /*
  48.  * The trapezoid fill algorithm uses trap_line structures to keep track of
  49.  * the left and right edges during the Bresenham loop.
  50.  */
  51. typedef struct trap_line_s {
  52.     /*
  53.      * h is the y extent of the line (edge.end.y - edge.start.y).
  54.      * We know h > 0.
  55.      */
  56.     fixed h;
  57.     /*
  58.      * The dx/dy ratio for the line is di + df/h.
  59.      * (The quotient refers to the l.s.b. of di, not fixed_1.)
  60.      * We know 0 <= df < h.
  61.      */
  62.     int di;
  63.     fixed df;
  64.     /*
  65.      * The current position within the scan line is x + xf/h + 1.
  66.      * (The 1 refers to the least significant bit of x, not fixed_1;
  67.      * similarly, the quotient refers to the l.s.b. of x.)
  68.      * We know -h <= xf < 0.
  69.      */
  70.     fixed x, xf;
  71.     /*
  72.      * We increment (x,xf) by (ldi,ldf) after each scan line.
  73.      * (ldi,ldf) is just (di,df) converted to fixed point.
  74.      * We know 0 <= ldf < h.
  75.      */
  76.     fixed ldi, ldf;
  77. } trap_line;
  78.  
  79. /*
  80.  * Compute the di and df members of a trap_line structure.  The x extent
  81.  * (edge.end.x - edge.start.x) is a parameter; the y extent (h member)
  82.  * has already been set.  Also adjust x for the initial y.
  83.  */
  84. inline private void
  85. compute_dx(trap_line *tl, fixed xd, fixed ys)
  86. {
  87.     fixed h = tl->h;
  88.     int di;
  89.  
  90.     if (xd >= 0) {
  91.     if (xd < h)
  92.         tl->di = 0, tl->df = xd;
  93.     else {
  94.         tl->di = di = (int)(xd / h);
  95.         tl->df = xd - di * h;
  96.         tl->x += ys * di;
  97.     }
  98.     } else {
  99.     if ((tl->df = xd + h) >= 0 /* xd >= -h */)
  100.         tl->di = -1, tl->x -= ys;
  101.     else {
  102.         tl->di = di = (int)-((h - 1 - xd) / h);
  103.         tl->df = xd - di * h;
  104.         tl->x += ys * di;
  105.     }
  106.     }
  107. }
  108.  
  109. #define YMULT_LIMIT (max_fixed / fixed_1)
  110.  
  111. /* Compute ldi, ldf, and xf similarly. */
  112. inline private void
  113. compute_ldx(trap_line *tl, fixed ys)
  114. {
  115.     int di = tl->di;
  116.     fixed df = tl->df;
  117.     fixed h = tl->h;
  118.  
  119.     if ( df < YMULT_LIMIT ) {
  120.      if ( df == 0 )        /* vertical edge, worth checking for */
  121.          tl->ldi = int2fixed(di), tl->ldf = 0, tl->xf = -h;
  122.      else {
  123.          tl->ldi = int2fixed(di) + int2fixed(df) / h;
  124.          tl->ldf = int2fixed(df) % h;
  125.          tl->xf =
  126.          (ys < fixed_1 ? ys * df % h : fixed_mult_rem(ys, df, h)) - h;
  127.      }
  128.     }
  129.     else {
  130.     tl->ldi = int2fixed(di) + fixed_mult_quo(fixed_1, df, h);
  131.     tl->ldf = fixed_mult_rem(fixed_1, df, h);
  132.     tl->xf = fixed_mult_rem(ys, df, h) - h;
  133.     }
  134. }
  135.  
  136. /*
  137.  * Fill a trapezoid.  left.start => left.end and right.start => right.end
  138.  * define the sides; ybot and ytop define the top and bottom.  Requires:
  139.  *      {left,right}->start.y <= ybot <= ytop <= {left,right}->end.y.
  140.  * Lines where left.x >= right.x will not be drawn.  Thanks to Paul Haeberli
  141.  * for an early floating point version of this algorithm.
  142.  */
  143. int
  144. gx_default_fill_trapezoid(gx_device * dev, const gs_fixed_edge * left,
  145.     const gs_fixed_edge * right, fixed ybot, fixed ytop, bool swap_axes,
  146.     const gx_device_color * pdevc, gs_logical_operation_t lop)
  147. {
  148.     const fixed ymin = fixed_pixround(ybot) + fixed_half;
  149.     const fixed ymax = fixed_pixround(ytop);
  150.  
  151.     if (ymin >= ymax)
  152.     return 0;        /* no scan lines to sample */
  153.     {
  154.     int iy = fixed2int_var(ymin);
  155.     const int iy1 = fixed2int_var(ymax);
  156.     trap_line l, r;
  157.     int rxl, rxr, ry;
  158.     const fixed
  159.         x0l = left->start.x, x1l = left->end.x, x0r = right->start.x,
  160.         x1r = right->end.x, dxl = x1l - x0l, dxr = x1r - x0r;
  161.     const fixed    /* partial pixel offset to first line to sample */
  162.         ysl = ymin - left->start.y, ysr = ymin - right->start.y;
  163.     fixed fxl;
  164.     bool fill_direct = color_writes_pure(pdevc, lop);
  165.     int max_rect_height = 1;  /* max height to do fill as rectangle */
  166.     int code;
  167.  
  168.     if_debug2('z', "[z]y=[%d,%d]\n", iy, iy1);
  169.  
  170.     l.h = left->end.y - left->start.y;
  171.     r.h = right->end.y - right->start.y;
  172.     l.x = x0l + (fixed_half - fixed_epsilon);
  173.     r.x = x0r + (fixed_half - fixed_epsilon);
  174.     ry = iy;
  175.  
  176. /*
  177.  * Free variables of FILL_TRAP_RECT:
  178.  *    swap_axes, pdevc, dev, lop
  179.  * Free variables of FILL_TRAP_RECT_DIRECT:
  180.  *    swap_axes, fill_rect, dev, cindex
  181.  */
  182. #define FILL_TRAP_RECT(x,y,w,h)\
  183.   (swap_axes ? gx_fill_rectangle_device_rop(y, x, h, w, pdevc, dev, lop) :\
  184.    gx_fill_rectangle_device_rop(x, y, w, h, pdevc, dev, lop))
  185. #define FILL_TRAP_RECT_DIRECT(x,y,w,h)\
  186.   (swap_axes ? (*fill_rect)(dev, y, x, h, w, cindex) :\
  187.    (*fill_rect)(dev, x, y, w, h, cindex))
  188.  
  189.     /* Compute the dx/dy ratios. */
  190.  
  191.     /*
  192.      * Compute the x offsets at the first scan line to sample.  We need
  193.      * to be careful in computing ys# * dx#f {/,%} h# because the
  194.      * multiplication may overflow.  We know that all the quantities
  195.      * involved are non-negative, and that ys# is usually less than 1 (as
  196.      * a fixed, of course); this gives us a cheap conservative check for
  197.      * overflow in the multiplication.
  198.      */
  199. #define YMULT_QUO(ys, tl)\
  200.   (ys < fixed_1 && tl.df < YMULT_LIMIT ? ys * tl.df / tl.h :\
  201.    fixed_mult_quo(ys, tl.df, tl.h))
  202.  
  203.     /*
  204.      * It's worth checking for dxl == dxr, since this is the case
  205.      * for parallelograms (including stroked lines).
  206.      * Also check for left or right vertical edges.
  207.      */
  208.     if (fixed_floor(l.x) == fixed_pixround(x1l)) {
  209.         /* Left edge is vertical, we don't need to increment. */
  210.         l.di = 0, l.df = 0;
  211.         fxl = 0;
  212.     } else {
  213.         compute_dx(&l, dxl, ysl);
  214.         fxl = YMULT_QUO(ysl, l);
  215.         l.x += fxl;
  216.     }
  217.     if (fixed_floor(r.x) == fixed_pixround(x1r)) {
  218.         /* Right edge is vertical.  If both are vertical, */
  219.         /* we have a rectangle. */
  220.         if (l.di == 0 && l.df == 0)
  221.         max_rect_height = max_int;
  222.         else
  223.         r.di = 0, r.df = 0;
  224.     }
  225.     /*
  226.      * The test for fxl != 0 is required because the right edge might
  227.      * cross some pixel centers even if the left edge doesn't.
  228.      */
  229.     else if (dxr == dxl && fxl != 0) {
  230.         if (l.di == 0)
  231.         r.di = 0, r.df = l.df;
  232.         else        /* too hard to do adjustments right */
  233.         compute_dx(&r, dxr, ysr);
  234.         if (ysr == ysl && r.h == l.h)
  235.         r.x += fxl;
  236.         else
  237.         r.x += YMULT_QUO(ysr, r);
  238.     } else {
  239.         compute_dx(&r, dxr, ysr);
  240.         r.x += YMULT_QUO(ysr, r);
  241.     }
  242.     rxl = fixed2int_var(l.x);
  243.     rxr = fixed2int_var(r.x);
  244.  
  245.     /*
  246.      * Take a shortcut if we're only sampling a single scan line,
  247.      * or if we have a rectangle.
  248.      */
  249.     if (iy1 - iy <= max_rect_height) {
  250.         iy = iy1 - 1;
  251.         if_debug2('z', "[z]rectangle, x=[%d,%d]\n", rxl, rxr);
  252.     } else {
  253.         /* Compute one line's worth of dx/dy. */
  254.         compute_ldx(&l, ysl);
  255.         if (dxr == dxl && ysr == ysl && r.h == l.h)
  256.         r.ldi = l.ldi, r.ldf = l.ldf, r.xf = l.xf;
  257.         else
  258.         compute_ldx(&r, ysr);
  259.     }
  260.  
  261. #define STEP_LINE(ix, tl)\
  262.   tl.x += tl.ldi;\
  263.   if ( (tl.xf += tl.ldf) >= 0 ) tl.xf -= tl.h, tl.x++;\
  264.   ix = fixed2int_var(tl.x)
  265.  
  266.     if (fill_direct) {
  267.         gx_color_index cindex = pdevc->colors.pure;
  268.         dev_proc_fill_rectangle((*fill_rect)) =
  269.         dev_proc(dev, fill_rectangle);
  270.  
  271.         while (++iy != iy1) {
  272.         int ixl, ixr;
  273.  
  274.         STEP_LINE(ixl, l);
  275.         STEP_LINE(ixr, r);
  276.         if (ixl != rxl || ixr != rxr) {
  277.             code = FILL_TRAP_RECT_DIRECT(rxl, ry, rxr - rxl, iy - ry);
  278.             if (code < 0)
  279.             goto xit;
  280.             rxl = ixl, rxr = ixr, ry = iy;
  281.         }
  282.         }
  283.         code = FILL_TRAP_RECT_DIRECT(rxl, ry, rxr - rxl, iy - ry);
  284.     } else {
  285.         while (++iy != iy1) {
  286.         int ixl, ixr;
  287.  
  288.         STEP_LINE(ixl, l);
  289.         STEP_LINE(ixr, r);
  290.         if (ixl != rxl || ixr != rxr) {
  291.             code = FILL_TRAP_RECT(rxl, ry, rxr - rxl, iy - ry);
  292.             if (code < 0)
  293.             goto xit;
  294.             rxl = ixl, rxr = ixr, ry = iy;
  295.         }
  296.         }
  297.         code = FILL_TRAP_RECT(rxl, ry, rxr - rxl, iy - ry);
  298.     }
  299. #undef STEP_LINE
  300. xit:    if (code < 0 && fill_direct)
  301.         return_error(code);
  302.     return_if_interrupt();
  303.     return code;
  304.     }
  305. }
  306.  
  307. /* Fill a parallelogram whose points are p, p+a, p+b, and p+a+b. */
  308. /* We should swap axes to get best accuracy, but we don't. */
  309. /* We must be very careful to follow the center-of-pixel rule in all cases. */
  310. int
  311. gx_default_fill_parallelogram(gx_device * dev,
  312.          fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
  313.           const gx_device_color * pdevc, gs_logical_operation_t lop)
  314. {
  315.     fixed t;
  316.     fixed qx, qy, ym;
  317.     dev_proc_fill_trapezoid((*fill_trapezoid));
  318.     gs_fixed_edge left, right;
  319.     int code;
  320.  
  321.     /* Make a special fast check for rectangles. */
  322.     if (PARALLELOGRAM_IS_RECT(ax, ay, bx, by)) {
  323.     gs_int_rect r;
  324.  
  325.     INT_RECT_FROM_PARALLELOGRAM(&r, px, py, ax, ay, bx, by);
  326.     return gx_fill_rectangle_device_rop(r.p.x, r.p.y, r.q.x - r.p.x,
  327.                         r.q.y - r.p.y, pdevc, dev, lop);
  328.     }
  329.     /*
  330.      * Not a rectangle.  Ensure that the 'a' line is to the left of
  331.      * the 'b' line.  Testing ax <= bx is neither sufficient nor
  332.      * necessary: in general, we need to compare the slopes.
  333.      */
  334.     /* Ensure ay >= 0, by >= 0. */
  335.     if (ay < 0)
  336.     px += ax, py += ay, ax = -ax, ay = -ay;
  337.     if (by < 0)
  338.     px += bx, py += by, bx = -bx, by = -by;
  339.     qx = px + ax + bx;
  340.     if ((ax ^ bx) < 0) {    /* In this case, the test ax <= bx is sufficient. */
  341.     if (ax > bx)
  342.         SWAP(ax, bx, t), SWAP(ay, by, t);
  343.     } else {            /*
  344.                  * Compare the slopes.  We know that ay >= 0, by >= 0,
  345.                  * and ax and bx have the same sign; the lines are in the
  346.                  * correct order iff
  347.                  *          ay/ax >= by/bx, or
  348.                  *          ay*bx >= by*ax
  349.                  * Eventually we can probably find a better way to test this,
  350.                  * without using floating point.
  351.                  */
  352.     if ((double)ay * bx < (double)by * ax)
  353.         SWAP(ax, bx, t), SWAP(ay, by, t);
  354.     }
  355.     fill_trapezoid = dev_proc(dev, fill_trapezoid);
  356.     qy = py + ay + by;
  357.     left.start.x = right.start.x = px;
  358.     left.start.y = right.start.y = py;
  359.     left.end.x = px + ax;
  360.     left.end.y = py + ay;
  361.     right.end.x = px + bx;
  362.     right.end.y = py + by;
  363. #define ROUNDED_SAME(p1, p2)\
  364.   (fixed_pixround(p1) == fixed_pixround(p2))
  365.     if (ay < by) {
  366.     if (!ROUNDED_SAME(py, left.end.y)) {
  367.         code = (*fill_trapezoid) (dev, &left, &right, py, left.end.y,
  368.                       false, pdevc, lop);
  369.         if (code < 0)
  370.         return code;
  371.     }
  372.     left.start = left.end;
  373.     left.end.x = qx, left.end.y = qy;
  374.     ym = right.end.y;
  375.     if (!ROUNDED_SAME(left.start.y, ym)) {
  376.         code = (*fill_trapezoid) (dev, &left, &right, left.start.y, ym,
  377.                       false, pdevc, lop);
  378.         if (code < 0)
  379.         return code;
  380.     }
  381.     right.start = right.end;
  382.     right.end.x = qx, right.end.y = qy;
  383.     } else {
  384.     if (!ROUNDED_SAME(py, right.end.y)) {
  385.         code = (*fill_trapezoid) (dev, &left, &right, py, right.end.y,
  386.                       false, pdevc, lop);
  387.         if (code < 0)
  388.         return code;
  389.     }
  390.     right.start = right.end;
  391.     right.end.x = qx, right.end.y = qy;
  392.     ym = left.end.y;
  393.     if (!ROUNDED_SAME(right.start.y, ym)) {
  394.         code = (*fill_trapezoid) (dev, &left, &right, right.start.y, ym,
  395.                       false, pdevc, lop);
  396.         if (code < 0)
  397.         return code;
  398.     }
  399.     left.start = left.end;
  400.     left.end.x = qx, left.end.y = qy;
  401.     }
  402.     if (!ROUNDED_SAME(ym, qy))
  403.     return (*fill_trapezoid) (dev, &left, &right, ym, qy,
  404.                   false, pdevc, lop);
  405.     else
  406.     return 0;
  407. #undef ROUNDED_SAME
  408. }
  409.  
  410. /* Fill a triangle whose points are p, p+a, and p+b. */
  411. /* We should swap axes to get best accuracy, but we don't. */
  412. int
  413. gx_default_fill_triangle(gx_device * dev,
  414.          fixed px, fixed py, fixed ax, fixed ay, fixed bx, fixed by,
  415.           const gx_device_color * pdevc, gs_logical_operation_t lop)
  416. {
  417.     fixed t;
  418.     fixed ym;
  419.  
  420.     dev_proc_fill_trapezoid((*fill_trapezoid)) =
  421.     dev_proc(dev, fill_trapezoid);
  422.     gs_fixed_edge left, right;
  423.     int code;
  424.  
  425.     /* Ensure ay >= 0, by >= 0. */
  426.     if (ay < 0)
  427.     px += ax, py += ay, bx -= ax, by -= ay, ax = -ax, ay = -ay;
  428.     if (by < 0)
  429.     px += bx, py += by, ax -= bx, ay -= by, bx = -bx, by = -by;
  430.     /* Ensure ay <= by. */
  431.     if (ay > by)
  432.     SWAP(ax, bx, t), SWAP(ay, by, t);
  433.     /*
  434.      * Make a special check for a flat bottom or top,
  435.      * which we can handle with a single call on fill_trapezoid.
  436.      */
  437.     left.start.x = right.start.x = px;
  438.     left.start.y = right.start.y = py;
  439.     if (ay == 0) {
  440.     /* Flat top */
  441.     if (ax < 0)
  442.         left.start.x = px + ax;
  443.     else
  444.         right.start.x = px + ax;
  445.     left.end.x = right.end.x = px + bx;
  446.     left.end.y = right.end.y = py + by;
  447.     ym = py;
  448.     } else if (ay == by) {
  449.     /* Flat bottom */
  450.     if (ax < bx)
  451.         left.end.x = px + ax, right.end.x = px + bx;
  452.     else
  453.         left.end.x = px + bx, right.end.x = px + ax;
  454.     left.end.y = right.end.y = py + by;
  455.     ym = py;
  456.     } else {
  457.     ym = py + ay;
  458.     if (fixed_mult_quo(bx, ay, by) < ax) {
  459.         /* The 'b' line is to the left of the 'a' line. */
  460.         left.end.x = px + bx, left.end.y = py + by;
  461.         right.end.x = px + ax, right.end.y = py + ay;
  462.         code = (*fill_trapezoid) (dev, &left, &right, py, ym,
  463.                       false, pdevc, lop);
  464.         right.start = right.end;
  465.         right.end = left.end;
  466.     } else {
  467.         /* The 'a' line is to the left of the 'b' line. */
  468.         left.end.x = px + ax, left.end.y = py + ay;
  469.         right.end.x = px + bx, right.end.y = py + by;
  470.         code = (*fill_trapezoid) (dev, &left, &right, py, ym,
  471.                       false, pdevc, lop);
  472.         left.start = left.end;
  473.         left.end = right.end;
  474.     }
  475.     if (code < 0)
  476.         return code;
  477.     }
  478.     return (*fill_trapezoid) (dev, &left, &right, ym, right.end.y,
  479.                   false, pdevc, lop);
  480. }
  481.  
  482. /* Draw a one-pixel-wide line. */
  483. int
  484. gx_default_draw_thin_line(gx_device * dev,
  485.               fixed fx0, fixed fy0, fixed fx1, fixed fy1,
  486.           const gx_device_color * pdevc, gs_logical_operation_t lop)
  487. {
  488.     int ix = fixed2int_var(fx0);
  489.     int iy = fixed2int_var(fy0);
  490.     int itox = fixed2int_var(fx1);
  491.     int itoy = fixed2int_var(fy1);
  492.  
  493.     return_if_interrupt();
  494.     if (itoy == iy) {        /* horizontal line */
  495.     return (ix <= itox ?
  496.         gx_fill_rectangle_device_rop(ix, iy, itox - ix + 1, 1,
  497.                          pdevc, dev, lop) :
  498.         gx_fill_rectangle_device_rop(itox, iy, ix - itox + 1, 1,
  499.                          pdevc, dev, lop)
  500.         );
  501.     }
  502.     if (itox == ix) {        /* vertical line */
  503.     return (iy <= itoy ?
  504.         gx_fill_rectangle_device_rop(ix, iy, 1, itoy - iy + 1,
  505.                          pdevc, dev, lop) :
  506.         gx_fill_rectangle_device_rop(ix, itoy, 1, iy - itoy + 1,
  507.                          pdevc, dev, lop)
  508.         );
  509.     } {
  510.     fixed h = fy1 - fy0;
  511.     fixed w = fx1 - fx0;
  512.     fixed tf;
  513.     bool swap_axes;
  514.     gs_fixed_edge left, right;
  515.  
  516.     if ((w < 0 ? -w : w) <= (h < 0 ? -h : h)) {
  517.         if (h < 0)
  518.         SWAP(fx0, fx1, tf), SWAP(fy0, fy1, tf),
  519.             h = -h;
  520.         right.start.x = (left.start.x = fx0 - fixed_half) + fixed_1;
  521.         right.end.x = (left.end.x = fx1 - fixed_half) + fixed_1;
  522.         left.start.y = right.start.y = fy0;
  523.         left.end.y = right.end.y = fy1;
  524.         swap_axes = false;
  525.     } else {
  526.         if (w < 0)
  527.         SWAP(fx0, fx1, tf), SWAP(fy0, fy1, tf),
  528.             w = -w;
  529.         right.start.x = (left.start.x = fy0 - fixed_half) + fixed_1;
  530.         right.end.x = (left.end.x = fy1 - fixed_half) + fixed_1;
  531.         left.start.y = right.start.y = fx0;
  532.         left.end.y = right.end.y = fx1;
  533.         swap_axes = true;
  534.     }
  535.     return (*dev_proc(dev, fill_trapezoid)) (dev, &left, &right,
  536.                          left.start.y, left.end.y,
  537.                          swap_axes, pdevc, lop);
  538.     }
  539. }
  540.  
  541. /* Stub out the obsolete procedure. */
  542. int
  543. gx_default_draw_line(gx_device * dev,
  544.              int x0, int y0, int x1, int y1, gx_color_index color)
  545. {
  546.     return -1;
  547. }
  548.  
  549. /* ---------------- Image drawing ---------------- */
  550.  
  551. /* GC structures for image enumerator */
  552. public_st_gx_image_enum_common();
  553.  
  554. private 
  555. ENUM_PTRS_WITH(image_enum_common_enum_ptrs, gx_image_enum_common_t *eptr)
  556.     return 0;
  557. case 0: return ENUM_OBJ(gx_device_enum_ptr(eptr->dev));
  558. ENUM_PTRS_END
  559.  
  560. private RELOC_PTRS_WITH(image_enum_common_reloc_ptrs, gx_image_enum_common_t *eptr)
  561. {
  562.     eptr->dev = gx_device_reloc_ptr(eptr->dev, gcst);
  563. }
  564. RELOC_PTRS_END
  565.  
  566. /*
  567.  * gx_default_begin_image is only invoked for ImageType 1 images.  However,
  568.  * the argument types are different, and if the device provides a
  569.  * begin_typed_image procedure, we should use it.  See gxdevice.h.
  570.  */
  571. private int
  572. gx_no_begin_image(gx_device * dev,
  573.           const gs_imager_state * pis, const gs_image_t * pim,
  574.           gs_image_format_t format, const gs_int_rect * prect,
  575.           const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
  576.           gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
  577. {
  578.     return -1;
  579. }
  580. int
  581. gx_default_begin_image(gx_device * dev,
  582.                const gs_imager_state * pis, const gs_image_t * pim,
  583.                gs_image_format_t format, const gs_int_rect * prect,
  584.           const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
  585.                gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
  586. {
  587.     /*
  588.      * Hand off to begin_typed_image, being careful to avoid a
  589.      * possible recursion loop.
  590.      */
  591.     dev_proc_begin_image((*save_begin_image)) = dev_proc(dev, begin_image);
  592.     gs_image_t image;
  593.     const gs_image_t *ptim;
  594.     int code;
  595.  
  596.     set_dev_proc(dev, begin_image, gx_no_begin_image);
  597.     if (pim->format == format)
  598.     ptim = pim;
  599.     else {
  600.     image = *pim;
  601.     image.format = format;
  602.     ptim = ℑ
  603.     }
  604.     code = (*dev_proc(dev, begin_typed_image))
  605.     (dev, pis, NULL, (const gs_image_common_t *)ptim, prect, pdcolor,
  606.      pcpath, memory, pinfo);
  607.     set_dev_proc(dev, begin_image, save_begin_image);
  608.     return code;
  609. }
  610.  
  611. int
  612. gx_default_begin_typed_image(gx_device * dev,
  613.             const gs_imager_state * pis, const gs_matrix * pmat,
  614.            const gs_image_common_t * pic, const gs_int_rect * prect,
  615.           const gx_drawing_color * pdcolor, const gx_clip_path * pcpath,
  616.               gs_memory_t * memory, gx_image_enum_common_t ** pinfo)
  617. {    /*
  618.      * If this is an ImageType 1 image using the imager's CTM,
  619.      * defer to begin_image.
  620.      */
  621.     if (pic->type->begin_typed_image == gx_begin_image1) {
  622.     const gs_image_t *pim = (const gs_image_t *)pic;
  623.  
  624.     if (pmat == 0 ||
  625.         (pis != 0 && !memcmp(pmat, &ctm_only(pis), sizeof(*pmat)))
  626.         ) {
  627.         int code = (*dev_proc(dev, begin_image))
  628.         (dev, pis, pim, pim->format, prect, pdcolor,
  629.          pcpath, memory, pinfo);
  630.  
  631.         if (code >= 0)
  632.         return code;
  633.     }
  634.     }
  635.     return (*pic->type->begin_typed_image)
  636.     (dev, pis, pmat, pic, prect, pdcolor, pcpath, memory, pinfo);
  637. }
  638.  
  639. /* Backward compatibility for obsolete driver procedures. */
  640.  
  641. int
  642. gx_default_image_data(gx_device *dev, gx_image_enum_common_t * info,
  643.               const byte ** plane_data,
  644.               int data_x, uint raster, int height)
  645. {
  646.     return gx_image_data(info, plane_data, data_x, raster, height);
  647. }
  648.  
  649. int
  650. gx_default_end_image(gx_device *dev, gx_image_enum_common_t * info,
  651.              bool draw_last)
  652. {
  653.     return gx_image_end(info, draw_last);
  654. }
  655.